home *** CD-ROM | disk | FTP | other *** search
/ PC World 2006 February / PCWorld_2006-02_cd.bin / software / vyzkuste / triky / triky.exe / httrack-3.33.exe / {app} / src / htscache.c < prev    next >
C/C++ Source or Header  |  2004-05-09  |  60KB  |  1,696 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       cache system (index and stores files in cache)         */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. /* Internal engine bytecode */
  39. #define HTS_INTERNAL_BYTECODE
  40.  
  41. #include "htscache.h"
  42.  
  43. /* specific definitions */
  44. #include "htsbase.h"
  45. #include "htsbasenet.h"
  46. #include "htsmd5.h"
  47. #include <time.h>
  48.  
  49. #include "htszlib.h"
  50.  
  51.  
  52. #include "htsnostatic.h"
  53. /* END specific definitions */
  54.  
  55. #undef test_flush
  56. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  57.  
  58. // routines de mise en cache
  59.  
  60. /*
  61.   VERSION 1.0 :
  62.   -----------
  63.  
  64. .ndx file
  65.  file with data
  66.    <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  67.  file without data
  68.    <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  69.  
  70. .dat file
  71.  [ file ] * 
  72. with
  73.   file= (with data)
  74.    [ bytes ] * sizeof(htsblk header) [ bytes ] * n(length of file given in htsblk header)
  75.  file= (without data)
  76.    [ bytes ] * sizeof(htsblk header)
  77. with
  78.  <string>(name) = <length in ascii>+<lf>+<data>
  79.  
  80.  
  81.   VERSION 1.1/1.2 :
  82.   ---------------
  83.  
  84. .ndx file
  85.  file with data
  86.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (datfile_position_ascii) ] * number_of_links
  87.  file without data
  88.    <string>("CACHE-1.1") <string>(date/time) [ <string>(hostname+filename) (-datfile_position_ascii) ] * number_of_links
  89.  
  90. .dat file
  91.    <string>("CACHE-1.1") [ [Header_1.1] [bytes] * n(length of file given in header) ] *
  92. with
  93.  Header_1.1=
  94.    <int>(statuscode)
  95.    <int>(size)
  96.    <string>(msg)
  97.    <string>(contenttype)
  98.    <string>(charset) [version 3]
  99.    <string>(last-modified)
  100.    <string>(Etag)
  101.    <string>location
  102.    <string>Content-disposition [version 2]
  103.    <string>hostname [version 4]
  104.    <string>URI filename [version 4]
  105.    <string>local filename [version 4]
  106.    [<string>"SD" <string>(supplemental data)]
  107.    [<string>"SD" <string>(supplemental data)]
  108.    ...
  109.    <string>"HTS" (end of header)
  110.    <int>(number of bytes of data) (0 if no data written)
  111. */
  112.  
  113. // Nouveau: si != text/html ne stocke que la taille
  114.  
  115.  
  116. void cache_mayadd(httrackp* opt,cache_back* cache,htsblk* r,char* url_adr,char* url_fil,char* url_save) {
  117.   if ((opt->debug>0) && (opt->log!=NULL)) {
  118.     fspc(opt->log,"debug"); fprintf(opt->log,"File checked by cache: %s"LF,url_adr);
  119.   }            
  120.   // ---stockage en cache---
  121.   // stocker dans le cache?
  122.   if (opt->cache) {
  123.     if (cache_writable(cache)) {
  124.       // c'est le seul endroit ou l'on ajoute des elements dans le cache (fichier entier ou header)
  125.       // on stocke tout fichier "ok", mais Θgalement les rΘponses 404,301,302...
  126.       if (
  127. #if 1
  128.         r->statuscode > 0
  129. #else
  130.         /* We don't store 5XX errors, because it might be a server problem */
  131.         (r->statuscode==200)        /* stocker rΘponse standard, plus */
  132.         || (r->statuscode==204)     /* no content */
  133.         || (r->statuscode==301)     /* moved perm */
  134.         || (r->statuscode==302)     /* moved temp */
  135.         || (r->statuscode==303)     /* moved temp */
  136.         || (r->statuscode==307)     /* moved temp */
  137.         || (r->statuscode==401)     /* authorization */
  138.         || (r->statuscode==403)     /* unauthorized */
  139.         || (r->statuscode==404)     /* not found */
  140.         || (r->statuscode==410)     /* gone */
  141. #endif
  142.         )
  143.       {        /* ne pas stocker si la page gΘnΘrΘe est une erreur */
  144.         if (!r->is_file) {
  145.           // stocker fichiers (et robots.txt)
  146.           if ( url_save == NULL || (strnotempty(url_save)) || (strcmp(url_fil,"/robots.txt")==0)) {
  147.             // ajouter le fichier au cache
  148.             cache_add(cache,*r,url_adr,url_fil,url_save,opt->all_in_cache);
  149.             //
  150.             // store a reference NOT to redo the same test zillions of times!
  151.             // (problem reported by Lars Clausen)
  152.             // we just store statuscode + location (if any)
  153.             if (url_save == NULL && r->statuscode / 100 >= 3) {
  154.               // cached "fast" header doesn't uet exists
  155.               if (inthash_read((inthash)cache->cached_tests, concat(url_adr, url_fil), NULL) == 0) {
  156.                 char BIGSTK tempo[HTS_URLMAXSIZE*2];
  157.                 sprintf(tempo, "%d", (int)r->statuscode);
  158.                 if (r->location != NULL && r->location[0] != '\0') {
  159.                   strcatbuff(tempo, "\n");
  160.                   strcatbuff(tempo, r->location);
  161.                 }
  162.                 if ((opt->debug>0) && (opt->log!=NULL)) {
  163.                   fspc(opt->log,"debug"); fprintf(opt->log, "Cached fast-header response: %s%s is %d"LF, url_adr, url_fil, (int)r->statuscode);
  164.                 }
  165.                 inthash_add((inthash)cache->cached_tests, concat(url_adr, url_fil), (long int)strdupt(tempo));
  166.               }
  167.             }
  168.           }
  169.         }
  170.       }
  171.     }
  172.   }
  173.   // ---fin stockage en cache---
  174. }
  175.  
  176.  
  177.  
  178. #if 01
  179.  
  180. /* test only - to be removed */
  181.  
  182. #define ZIP_FIELD_STRING(headers, headersSize, field, value) do { \
  183.   if ( (value != NULL) && (value)[0] != '\0') { \
  184.     sprintf(headers + headersSize, "%s: %s\r\n", field, (value != NULL) ? (value) : ""); \
  185.     (headersSize) += (int) strlen(headers + headersSize); \
  186.   } \
  187. } while(0)
  188. #define ZIP_FIELD_INT(headers, headersSize, field, value) do { \
  189.   if ( (value != 0) ) { \
  190.     sprintf(headers + headersSize, "%s: "LLintP"\r\n", field, (LLint)(value)); \
  191.     (headersSize) += (int) strlen(headers + headersSize); \
  192.   } \
  193. } while(0)
  194. #define ZIP_FIELD_INT_FORCE(headers, headersSize, field, value) do { \
  195.   sprintf(headers + headersSize, "%s: "LLintP"\r\n", field, (LLint)(value)); \
  196.   (headersSize) += (int) strlen(headers + headersSize); \
  197. } while(0)
  198.  
  199. struct cache_back_zip_entry {
  200.   unsigned long int hdrPos;
  201.   unsigned long int size;
  202.   int compressionMethod;
  203. };
  204.  
  205. #define ZIP_READFIELD_STRING(line, value, refline, refvalue) do { \
  206.   if (line[0] != '\0' && strfield2(line, refline)) { \
  207.     strcpybuff(refvalue, value); \
  208.     line[0] = '\0'; \
  209.   } \
  210. } while(0)
  211. #define ZIP_READFIELD_INT(line, value, refline, refvalue) do { \
  212.   if (line[0] != '\0' && strfield2(line, refline)) { \
  213.     int intval = 0; \
  214.     sscanf(value, "%d", &intval); \
  215.     (refvalue) = intval; \
  216.     line[0] = '\0'; \
  217.   } \
  218. } while(0)
  219.  
  220.  
  221. /* Ajout d'un fichier en cache */
  222. void cache_add(cache_back* cache,htsblk r,char* url_adr,char* url_fil,char* url_save,int all_in_cache) {
  223.   char BIGSTK filemame[HTS_URLMAXSIZE*4];
  224.   int dataincache=0;    // put data in cache ?
  225.   char BIGSTK headers[8192];
  226.   int headersSize = 0;
  227.   int entryBodySize = 0;
  228.   int entryFilenameSize = 0;
  229.   zip_fileinfo fi;
  230.  
  231.   // robots.txt hack
  232.   if (url_save == NULL) {
  233.     dataincache=0;        // testing links
  234.   }
  235.   else {
  236.     if ( (strnotempty(url_save)==0) ) {
  237.       if (strcmp(url_fil,"/robots.txt")==0)        // robots.txt
  238.         dataincache=1;
  239.       else
  240.         return;   // error (except robots.txt)
  241.     }
  242.  
  243.     /* Data in cache ? */
  244.     if (is_hypertext_mime(r.contenttype, url_fil))
  245.       dataincache=1;
  246.     else if (all_in_cache)
  247.       dataincache=1;
  248.   }
  249.  
  250.   if (r.size < 0)   // error
  251.     return;
  252.  
  253.   // data in cache
  254.   if (dataincache) {
  255.     assertf(((int) r.size) == r.size);
  256.     entryBodySize = (int) r.size;
  257.   }
  258.  
  259.   /* Fields */
  260.   headers[0] = '\0';
  261.   headersSize = 0;
  262.   /* */
  263.   {
  264.     char* message;
  265.     if (strlen(r.msg) < 32) {
  266.       message = r.msg;
  267.     } else {
  268.       message = "(See X-StatusMessage)";
  269.     }
  270.     /* 64 characters MAX for first line */
  271.     sprintf(headers + headersSize, "HTTP/1.%c %d %s\r\n", '1', r.statuscode, r.msg);
  272.   }
  273.   headersSize += (int) strlen(headers + headersSize);
  274.   /* Second line MUST ALWAYS be X-In-Cache */
  275.   ZIP_FIELD_INT_FORCE(headers, headersSize, "X-In-Cache", dataincache);
  276.   ZIP_FIELD_INT(headers, headersSize, "X-StatusCode", r.statuscode);
  277.   ZIP_FIELD_STRING(headers, headersSize, "X-StatusMessage", r.msg);
  278.   ZIP_FIELD_INT(headers, headersSize, "X-Size", r.size);           // size
  279.   ZIP_FIELD_STRING(headers, headersSize, "Content-Type", r.contenttype);      // contenttype
  280.   ZIP_FIELD_STRING(headers, headersSize, "X-Charset", r.charset);          // contenttype
  281.   ZIP_FIELD_STRING(headers, headersSize, "Last-Modified", r.lastmodified);     // last-modified
  282.   ZIP_FIELD_STRING(headers, headersSize, "Etag", r.etag);             // Etag
  283.   ZIP_FIELD_STRING(headers, headersSize, "Location", r.location);         // 'location' pour moved
  284.   ZIP_FIELD_STRING(headers, headersSize, "Content-Disposition", r.cdispo);           // Content-disposition
  285.   ZIP_FIELD_STRING(headers, headersSize, "X-Addr", url_adr);            // Original address
  286.   ZIP_FIELD_STRING(headers, headersSize, "X-Fil", url_fil);            // Original URI filename
  287.   ZIP_FIELD_STRING(headers, headersSize, "X-Save", url_save);           // Original save filename
  288.   
  289.   entryFilenameSize = (int) ( strlen(url_adr) + strlen(url_fil));
  290.   
  291.   /* Filename */
  292.   if (!link_has_authority(url_adr)) {
  293.     strcpybuff(filemame, "http://");
  294.   } else {
  295.     strcpybuff(filemame, "");
  296.   }
  297.   strcatbuff(filemame, url_adr);
  298.   strcatbuff(filemame, url_fil);
  299.  
  300.   /* Time */
  301.   memset(&fi, 0, sizeof(fi));
  302.   if (r.lastmodified[0] != '\0') {
  303.     struct tm* tm_s=convert_time_rfc822(r.lastmodified);
  304.     if (tm_s) {
  305.       fi.tmz_date.tm_sec = (uInt) tm_s->tm_sec;
  306.       fi.tmz_date.tm_min = (uInt) tm_s->tm_min;
  307.       fi.tmz_date.tm_hour = (uInt) tm_s->tm_hour;
  308.       fi.tmz_date.tm_mday = (uInt) tm_s->tm_mday;
  309.       fi.tmz_date.tm_mon = (uInt) tm_s->tm_mon;
  310.       fi.tmz_date.tm_year = (uInt) tm_s->tm_year;
  311.     }
  312.   }
  313.   
  314.   /* Open file - NOTE: headers in "comment" */
  315.   if (zipOpenNewFileInZip((zipFile) cache->zipOutput,
  316.     filemame,
  317.     &fi,
  318.     /* 
  319.     Store headers in realtime in the local file directory as extra field
  320.     In case of crash, we'll be able to recover the whole ZIP file by rescanning it
  321.     */
  322.     headers,
  323.     (uInt) strlen(headers),
  324.     NULL,
  325.     0,
  326.     NULL, /* comment */
  327.     Z_DEFLATED,
  328.     Z_DEFAULT_COMPRESSION) != Z_OK)
  329.   {
  330.     int zip_disk_write_failed = 0;
  331.     assertf(zip_disk_write_failed);
  332.   }
  333.   
  334.   /* Write data in cache */
  335.   if (dataincache) {
  336.     if (r.is_write == 0) {
  337.       if (r.size > 0 && r.adr != NULL) {
  338.         if (zipWriteInFileInZip((zipFile) cache->zipOutput, r.adr, (int) r.size) != Z_OK) {
  339.           int zip_disk_write_failed = 0;
  340.           assertf(zip_disk_write_failed);
  341.         }
  342.       }
  343.     } else {
  344.       FILE* fp;
  345.       // On recopie le fichier..
  346.       LLint file_size=fsize(fconv(url_save));
  347.       if (file_size>=0) {
  348.         fp=fopen(fconv(url_save),"rb");
  349.         if (fp!=NULL) {
  350.           char BIGSTK buff[32768];
  351.           INTsys nl;
  352.           do {
  353.             nl=fread(buff,1,32768,fp);
  354.             if (nl>0) { 
  355.               if (zipWriteInFileInZip((zipFile) cache->zipOutput, buff, (int) nl) != Z_OK) {
  356.                 int zip_disk_write_failed = 0;
  357.                 assertf(zip_disk_write_failed);
  358.               }
  359.             }
  360.           } while(nl>0);
  361.           fclose(fp);
  362.         } else {
  363.           /* Err FIXME - lost file */
  364.         }
  365.       } /* Empty files are OK */
  366.     }
  367.   }
  368.   
  369.   /* Close */
  370.   if (zipCloseFileInZip((zipFile) cache->zipOutput) != Z_OK) {
  371.     int zip_disk_write_failed = 0;
  372.     assertf(zip_disk_write_failed);
  373.   }
  374.  
  375.   /* Flush */
  376.   if (zipFlush((zipFile) cache->zipOutput) != 0) {
  377.     int zip_disk_write_failed = 0;
  378.     assertf(zip_disk_write_failed);
  379.   }
  380. }
  381.  
  382. #else
  383.  
  384. /* Ajout d'un fichier en cache */
  385. void cache_add(cache_back* cache,htsblk r,char* url_adr,char* url_fil,char* url_save,int all_in_cache) {
  386.   int pos;
  387.   char s[256];
  388.   char BIGSTK buff[HTS_URLMAXSIZE*4];
  389.   int ok=1;
  390.   int dataincache=0;    // donnΘe en cache?
  391.   FILE* cache_ndx = cache->ndx;
  392.   FILE* cache_dat = cache->dat;
  393.   /*char digest[32+2];*/
  394.   /*digest[0]='\0';*/
  395.  
  396.   // Longueur url_save==0?
  397.   if ( (strnotempty(url_save)==0) ) {
  398.     if (strcmp(url_fil,"/robots.txt")==0)        // robots.txt
  399.       dataincache=1;
  400.     else if (strcmp(url_fil,"/test")==0)        // testing links
  401.       dataincache=0;
  402.     else
  403.       return;   // erreur (sauf robots.txt)
  404.   }
  405.  
  406.   if (r.size <= 0)   // taille <= 0 
  407.     return;          // refusΘ..
  408.  
  409.   // Mettre les *donΘes* en cache ?
  410.   if (is_hypertext_mime(r.contenttype, url_fil))    // html, mise en cache des donnΘes et 
  411.     dataincache=1;                               // pas uniquement de l'en tΩte
  412.   else if (all_in_cache)
  413.     dataincache=1;                               // forcer tout en cache
  414.  
  415.   /* calcul md5 ? */
  416.   /*
  417.   if (is_hypertext_mime(r.contenttype)) {    // html, calcul MD5
  418.     if (r.adr) {
  419.       domd5mem(r.adr,r.size,digest,1);
  420.     }
  421.   }*/
  422.  
  423.   // Position
  424.   fflush(cache_dat); fflush(cache_ndx);
  425.   pos=ftell(cache_dat);
  426.   // Θcrire pointeur seek, adresse, fichier
  427.   if (dataincache)   // patcher
  428.     sprintf(s,"%d\n",pos);    // ecrire tel que (eh oui Θvite les \0..)
  429.   else
  430.     sprintf(s,"%d\n",-pos);   // ecrire tel que (eh oui Θvite les \0..)
  431.  
  432.   // data
  433.   // Θcrire donnΘes en-tΩte, donnΘes fichier
  434.   /*if (!dataincache) {   // patcher
  435.     r.size=-r.size;  // nΘgatif
  436.   }*/
  437.  
  438.   // Construction header
  439.   ok=0;
  440.   if (cache_wint(cache_dat,r.statuscode) != -1       // statuscode
  441.   && cache_wLLint(cache_dat,r.size) != -1           // size
  442.   && cache_wstr(cache_dat,r.msg) != -1              // msg
  443.   && cache_wstr(cache_dat,r.contenttype) != -1      // contenttype
  444.   && cache_wstr(cache_dat,r.charset) != -1          // contenttype
  445.   && cache_wstr(cache_dat,r.lastmodified) != -1     // last-modified
  446.   && cache_wstr(cache_dat,r.etag) != -1             // Etag
  447.   && cache_wstr(cache_dat,(r.location!=NULL)?r.location:"") != -1         // 'location' pour moved
  448.   && cache_wstr(cache_dat,r.cdispo) != -1           // Content-disposition
  449.   && cache_wstr(cache_dat,url_adr) != -1            // Original address
  450.   && cache_wstr(cache_dat,url_fil) != -1            // Original URI filename
  451.   && cache_wstr(cache_dat,url_save) != -1           // Original save filename
  452.   && cache_wstr(cache_dat,r.headers) != -1          // Full HTTP Headers
  453.   && cache_wstr(cache_dat,"HTS") != -1              // end of header
  454.   ) {
  455.     ok=1;       /* ok */
  456.   }
  457.   // Fin construction header
  458.  
  459.   /*if ((int) fwrite((char*) &r,1,sizeof(htsblk),cache_dat) == sizeof(htsblk)) {*/
  460.   if (ok) {
  461.     if (dataincache) {    // mise en cache?
  462.       if (!r.adr) {       /* taille nulle (parfois en cas de 301 */
  463.         if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  464.           ok=0;
  465.       } else if (r.is_write==0) {  // en mΘmoire, recopie directe
  466.         if (cache_wLLint(cache_dat,r.size)!=-1) {
  467.           if (r.size>0) {   // taille>0
  468.             if (fwrite(r.adr,1,(INTsys)r.size,cache_dat)!=r.size)
  469.               ok=0;
  470.           } else    // taille=0, ne rien Θcrire
  471.             ok=0;
  472.         } else
  473.           ok=0;
  474.       } else {  // recopier fichier dans cache
  475.         FILE* fp;
  476.         // On recopie le fichier..
  477.         LLint file_size=fsize(fconv(url_save));
  478.         if (file_size>=0) {
  479.           if (cache_wLLint(cache_dat,file_size)!=-1) {
  480.             fp=fopen(fconv(url_save),"rb");
  481.             if (fp!=NULL) {
  482.               char BIGSTK buff[32768];
  483.               INTsys nl;
  484.               do {
  485.                 nl=fread(buff,1,32768,fp);
  486.                 if (nl>0) { 
  487.                   if ((INTsys)fwrite(buff,1,(INTsys)nl,cache_dat)!=nl) {  // erreur
  488.                     nl=-1;
  489.                     ok=0;
  490.                   }
  491.                 }
  492.               } while(nl>0);
  493.               fclose(fp);
  494.             } else ok=0;
  495.           } else ok=0;
  496.         } else ok=0;
  497.       }
  498.     } else {
  499.       if (cache_wLLint(cache_dat,0)==-1)          /* 0 bytes */
  500.         ok=0;
  501.     }
  502.   } else ok=0;
  503.   /*if (!dataincache) {   // dΘpatcher
  504.     r.size=-r.size;
  505.   }*/
  506.  
  507.   // index
  508.   // adresse+cr+fichier+cr
  509.   if (ok) {
  510.     buff[0]='\0'; strcatbuff(buff,url_adr); strcatbuff(buff,"\n"); strcatbuff(buff,url_fil); strcatbuff(buff,"\n");
  511.     cache_wstr(cache_ndx,buff);
  512.     fwrite(s,1,strlen(s),cache_ndx);
  513.   }  // si ok=0 on a peut Ωtre Θcrit des donnΘes pour rien mais on s'en tape
  514.   
  515.   // en cas de plantage, on aura au moins le cache!
  516.   fflush(cache_dat); fflush(cache_ndx);
  517. }
  518.  
  519. #endif
  520.  
  521.  
  522. htsblk cache_read(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location) {
  523.   return cache_readex(opt,cache,adr,fil,save,location,NULL,0);
  524. }
  525.  
  526. htsblk cache_read_ro(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location) {
  527.   return cache_readex(opt,cache,adr,fil,save,location,NULL,1);
  528. }
  529.  
  530. static htsblk cache_readex_old(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  531.                                char* return_save, int readonly);
  532.  
  533. static htsblk cache_readex_new(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  534.                                char* return_save, int readonly);
  535.  
  536. // lecture d'un fichier dans le cache
  537. // si save==null alors test unqiquement
  538. htsblk cache_readex(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  539.                     char* return_save, int readonly) {
  540.   if (cache->zipInput != NULL) {
  541.     return cache_readex_new(opt, cache, adr, fil, save, location, return_save, readonly);
  542.   } else {
  543.     return cache_readex_old(opt, cache, adr, fil, save, location, return_save, readonly);
  544.   }
  545. }
  546.  
  547. // lecture d'un fichier dans le cache
  548. // si save==null alors test unqiquement
  549. static htsblk cache_readex_new(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  550.                                char* return_save, int readonly) {
  551.   char BIGSTK location_default[HTS_URLMAXSIZE*2];
  552.   char BIGSTK buff[HTS_URLMAXSIZE*2];
  553.   char BIGSTK previous_save[HTS_URLMAXSIZE*2];
  554.   long int hash_pos;
  555.   int hash_pos_return;
  556.   htsblk r;
  557.   memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  558.  
  559.   if (location) {
  560.     r.location = location;
  561.   } else {
  562.     r.location = location_default;
  563.   }
  564.   strcpybuff(r.location, ""); 
  565.   strcpybuff(buff, adr);
  566.   strcatbuff(buff,fil);
  567.   hash_pos_return = inthash_read((inthash)cache->hashtable, buff, (long int*)&hash_pos);
  568.   /* avoid errors on data entries */
  569.   if (adr[0] == '/' && adr[1] == '/' && adr[2] == '[') {
  570. #if HTS_FAST_CACHE
  571.     hash_pos_return = 0;
  572. #else
  573.     a = NULL;
  574. #endif
  575.   }
  576.  
  577.   if (hash_pos_return) {
  578.     uLong posInZip;
  579.     if (hash_pos > 0) {
  580.       posInZip = (uLong) hash_pos;
  581.     } else {
  582.       posInZip = (uLong) -hash_pos;
  583.     }
  584.     if (unzSetOffset((unzFile) cache->zipInput, posInZip) == Z_OK) {
  585.       /* Read header (Max 8KiB) */
  586.       if (unzOpenCurrentFile((unzFile) cache->zipInput) == Z_OK) {
  587.         char BIGSTK headerBuff[8192 + 2];
  588.         int readSizeHeader;
  589.         int totalHeader = 0;
  590.         int dataincache = 0;
  591.         
  592.         /* For BIG comments */
  593.         headerBuff[0] 
  594.           = headerBuff[sizeof(headerBuff) - 1] 
  595.           = headerBuff[sizeof(headerBuff) - 2] 
  596.           = headerBuff[sizeof(headerBuff) - 3] = '\0';
  597.  
  598.         if ( (readSizeHeader = unzGetLocalExtrafield((unzFile) cache->zipInput, headerBuff, sizeof(headerBuff) - 2)) > 0) 
  599.         /*if (unzGetCurrentFileInfo((unzFile) cache->zipInput, NULL,
  600.           NULL, 0, NULL, 0, headerBuff, sizeof(headerBuff) - 2) == Z_OK ) */
  601.         {
  602.           int offset = 0;
  603.           char BIGSTK line[HTS_URLMAXSIZE + 2];
  604.           int lineEof = 0;
  605.           /*readSizeHeader = (int) strlen(headerBuff);*/
  606.           headerBuff[readSizeHeader] = '\0';
  607.           do {
  608.             char* value;
  609.             line[0] = '\0';
  610.             offset += binput(headerBuff + offset, line, sizeof(line) - 2);
  611.             if (line[0] == '\0') {
  612.               lineEof = 1;
  613.             }
  614.             value = strchr(line, ':');
  615.             if (value != NULL) {
  616.               *value++ = '\0';
  617.               if (*value == ' ' || *value == '\t') value++;
  618.               ZIP_READFIELD_INT(line, value, "X-In-Cache", dataincache);
  619.               ZIP_READFIELD_INT(line, value, "X-Statuscode", r.statuscode);
  620.               ZIP_READFIELD_STRING(line, value, "X-StatusMessage", r.msg);              // msg
  621.               ZIP_READFIELD_INT(line, value, "X-Size", r.size);           // size
  622.               ZIP_READFIELD_STRING(line, value, "Content-Type", r.contenttype);      // contenttype
  623.               ZIP_READFIELD_STRING(line, value, "X-Charset", r.charset);          // contenttype
  624.               ZIP_READFIELD_STRING(line, value, "Last-Modified", r.lastmodified);     // last-modified
  625.               ZIP_READFIELD_STRING(line, value, "Etag", r.etag);             // Etag
  626.               ZIP_READFIELD_STRING(line, value, "Location", r.location);         // 'location' pour moved
  627.               ZIP_READFIELD_STRING(line, value, "Content-Disposition", r.cdispo);           // Content-disposition
  628.               ZIP_READFIELD_STRING(line, value, "X-Addr", previous_save);            // Original address
  629.               ZIP_READFIELD_STRING(line, value, "X-Fil", previous_save);            // Original URI filename
  630.               ZIP_READFIELD_STRING(line, value, "X-Save", previous_save);           // Original save filename
  631.             }
  632.           } while(offset < readSizeHeader && !lineEof);
  633.           totalHeader = offset;
  634.  
  635.           /* Complete fields */
  636.           r.totalsize=r.size;
  637.           r.adr=NULL;
  638.           r.out=NULL;
  639.           r.fp=NULL;
  640.           
  641.           if (save != NULL) {     /* ne pas lire uniquement header */
  642.             int ok = 0;
  643.                        
  644. #if HTS_DIRECTDISK
  645.             // Court-circuit:
  646.             // Peut-on stocker le fichier directement sur disque?
  647.             if (ok) {
  648.               if (r.msg[0] == '\0') {
  649.                 strcpybuff(r.msg,"Cache Read Error : Unexpected error");
  650.               }
  651.             }
  652.             else if (!readonly && r.statuscode==200 && !is_hypertext_mime(r.contenttype, fil) && strnotempty(save)) {    // pas HTML, Θcrire sur disk directement
  653.               
  654.               r.is_write=1;    // Θcrire
  655.               if (fexist(fconv(save))) {  // un fichier existe dΘja
  656.                 //if (fsize(fconv(save))==r.size) {  // mΩme taille -- NON tant pis (taille mal declaree)
  657.                 ok=1;    // plus rien α faire
  658.                 filenote(save,NULL);        // noter comme connu
  659.               }
  660.               
  661.               if (!dataincache && !ok) { // Pas de donnΘe en cache et fichier introuvable : erreur!
  662.                 if (opt->norecatch) {
  663.                   filecreateempty(save);
  664.                   //
  665.                   r.statuscode=-1;
  666.                   strcpybuff(r.msg,"File deleted by user not recaught");
  667.                   ok=1;     // ne pas rΘcupΘrer (et pas d'erreur)
  668.                 } else {
  669.                   r.statuscode=-1;
  670.                   strcpybuff(r.msg,"Previous cache file not found");
  671.                   ok=1;    // ne pas rΘcupΘrer
  672.                 }
  673.               }
  674.               
  675.               if (!ok) {  
  676.                 r.out=filecreate(save);
  677. #if HDEBUG
  678.                 printf("direct-disk: %s\n",save);
  679. #endif
  680.                 if (r.out!=NULL) {
  681.                   char BIGSTK buff[32768+4];
  682.                   LLint size = r.size;
  683.                   if (size > 0) {
  684.                     INTsys nl;
  685.                     do {
  686.                       nl = unzReadCurrentFile((unzFile) cache->zipInput, buff, (int)minimum(size, 32768));
  687.                       if (nl>0) {
  688.                         size-=nl; 
  689.                         if ((INTsys)fwrite(buff,1,(INTsys)nl,r.out)!=nl) {  // erreur
  690.                           r.statuscode=-1;
  691.                           strcpybuff(r.msg,"Cache Read Error : Read To Disk");
  692.                         }
  693.                       }
  694.                     } while((nl>0) && (size>0) && (r.statuscode!=-1));
  695.                   }
  696.                   
  697.                   fclose(r.out);
  698.                   r.out=NULL;
  699. #if HTS_WIN==0
  700.                   chmod(save,HTS_ACCESS_FILE);      
  701. #endif          
  702.                   //xxusercommand(opt,0,NULL,fconv(save), adr, fil);
  703.                 } else {
  704.                   r.statuscode=-1;
  705.                   strcpybuff(r.msg,"Cache Write Error : Unable to Create File");
  706.                   //printf("%s\n",save);
  707.                 }
  708.               }
  709.               
  710.             } else
  711. #endif
  712.             { // lire en mΘmoire
  713.               
  714.               if (!dataincache) {
  715.                 if (strnotempty(save)) { // Pas de donnΘe en cache, bizarre car html!!!
  716.                   r.statuscode=-1;
  717.                   strcpybuff(r.msg,"Previous cache file not found (2)");
  718.                 } else {                 /* Read in memory from cache */
  719.                   if (strnotempty(return_save) && fexist(return_save)) {
  720.                     FILE* fp = fopen(fconv(return_save), "rb");
  721.                     if (fp != NULL) {
  722.                       r.adr=(char*) malloct((INTsys)r.size + 4);
  723.                       if (adr != NULL) {
  724.                         if (r.size > 0 && fread(r.adr, 1, (INTsys) r.size, fp) != r.size) {
  725.                           r.statuscode=-1;
  726.                           strcpybuff(r.msg,"Read error in cache disk data");
  727.                         }
  728.                       } else {
  729.                         r.statuscode=-1;
  730.                         strcpybuff(r.msg,"Read error (memory exhausted) from cache");
  731.                       }
  732.                       fclose(fp);
  733.                     }
  734.                   } else {
  735.                     r.statuscode=-1;
  736.                     strcpybuff(r.msg,"Cache file not found on disk");
  737.                   }
  738.                 }
  739.               } else {
  740.                 // lire fichier (d'un coup)
  741.                 r.adr=(char*) malloct((INTsys)r.size+4);
  742.                 if (r.adr!=NULL) {
  743.                   if (unzReadCurrentFile((unzFile) cache->zipInput, r.adr, (INTsys)r.size) != r.size) {  // erreur
  744.                     freet(r.adr);
  745.                     r.adr=NULL;
  746.                     r.statuscode=-1;
  747.                     strcpybuff(r.msg,"Cache Read Error : Read Data");
  748.                   } else
  749.                     *(r.adr+r.size)='\0';
  750.                   //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  751.                 } else {  // erreur
  752.                   r.statuscode=-1;
  753.                   strcpybuff(r.msg,"Cache Memory Error");
  754.                 }
  755.               }
  756.             }
  757.           }    // si save==null, ne rien charger (juste en tΩte)
  758.  
  759.  
  760.         } else {
  761.           r.statuscode=-1;
  762.           strcpybuff(r.msg,"Cache Read Error : Read Header Data");
  763.         }
  764.         unzCloseCurrentFile((unzFile) cache->zipInput);
  765.       } else {
  766.         r.statuscode=-1;
  767.         strcpybuff(r.msg,"Cache Read Error : Open File");
  768.       }
  769.  
  770.     } else {
  771.       r.statuscode=-1;
  772.       strcpybuff(r.msg,"Cache Read Error : Bad Offset");
  773.     }
  774.   } else {
  775.     r.statuscode=-1;
  776.     strcpybuff(r.msg,"File Cache Entry Not Found");
  777.   }
  778.   if (!location) {   /* don't export internal buffer */
  779.     r.location = NULL;
  780.   }
  781.   return r;
  782. }
  783.  
  784.  
  785. // lecture d'un fichier dans le cache
  786. // si save==null alors test unqiquement
  787. static htsblk cache_readex_old(httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* location,
  788.                                char* return_save, int readonly) {
  789. #if HTS_FAST_CACHE
  790.   long int hash_pos;
  791.   int hash_pos_return;
  792. #else
  793.   char* a;
  794. #endif
  795.   char BIGSTK buff[HTS_URLMAXSIZE*2];
  796.   char BIGSTK location_default[HTS_URLMAXSIZE*2];
  797.   char BIGSTK previous_save[HTS_URLMAXSIZE*2];
  798.   htsblk r;
  799.   int ok=0;
  800.   int header_only=0;
  801.  
  802.   memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  803.   if (location) {
  804.     r.location = location;
  805.   } else {
  806.     r.location = location_default;
  807.   }
  808.   strcpybuff(r.location, ""); 
  809. #if HTS_FAST_CACHE
  810.   strcpybuff(buff,adr); strcatbuff(buff,fil);
  811.   hash_pos_return=inthash_read((inthash)cache->hashtable,buff,(long int*)&hash_pos);
  812. #else
  813.   buff[0]='\0'; strcatbuff(buff,"\n"); strcatbuff(buff,adr); strcatbuff(buff,"\n"); strcatbuff(buff,fil); strcatbuff(buff,"\n");
  814.   if (cache->use)
  815.     a=strstr(cache->use,buff);
  816.   else
  817.     a=NULL;       // forcer erreur
  818. #endif
  819.  
  820.   /* avoid errors on data entries */
  821.   if (adr[0] == '/' && adr[1] == '/' && adr[2] == '[') {
  822. #if HTS_FAST_CACHE
  823.     hash_pos_return = 0;
  824. #else
  825.     a = NULL;
  826. #endif
  827.   }
  828.  
  829.   // en cas de succΦs
  830. #if HTS_FAST_CACHE
  831.   if (hash_pos_return) {
  832. #else
  833.   if (a!=NULL) {  // OK existe en cache!
  834. #endif
  835.     INTsys pos;
  836. #if DEBUGCA
  837.     fprintf(stdout,"..cache: %s%s at ",adr,fil);
  838. #endif
  839.     
  840. #if HTS_FAST_CACHE
  841.     pos=hash_pos;     /* simply */
  842. #else
  843.     a+=strlen(buff);
  844.     sscanf(a,"%d",&pos);    // lire position
  845. #endif
  846. #if DEBUGCA
  847.     printf("%d\n",pos);
  848. #endif
  849.  
  850.     fflush(cache->olddat); 
  851.     if (fseek(cache->olddat,((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  852.       /* Importer cache1.0 */
  853.       if (cache->version==0) {
  854.         OLD_htsblk old_r;
  855.         if (fread((char*) &old_r,1,sizeof(old_r),cache->olddat)==sizeof(old_r)) { // lire tout (y compris statuscode etc)
  856.           r.statuscode=old_r.statuscode;
  857.           r.size=old_r.size;        // taille fichier
  858.           strcpybuff(r.msg,old_r.msg);
  859.           strcpybuff(r.contenttype,old_r.contenttype);
  860.           ok=1;     /* import  ok */
  861.         }
  862.       /* */
  863.       /* Cache 1.1 */
  864.       } else {
  865.         char check[256];
  866.         LLint size_read;
  867.         check[0]='\0';
  868.         //
  869.         cache_rint(cache->olddat,&r.statuscode);
  870.         cache_rLLint(cache->olddat,&r.size);
  871.         cache_rstr(cache->olddat,r.msg);
  872.         cache_rstr(cache->olddat,r.contenttype);
  873.         if (cache->version >= 3)
  874.           cache_rstr(cache->olddat,r.charset);
  875.         cache_rstr(cache->olddat,r.lastmodified);
  876.         cache_rstr(cache->olddat,r.etag);
  877.         cache_rstr(cache->olddat,r.location);
  878.         if (cache->version >= 2)
  879.           cache_rstr(cache->olddat,r.cdispo);
  880.         if (cache->version >= 4) {
  881.           cache_rstr(cache->olddat, previous_save);  // adr
  882.           cache_rstr(cache->olddat, previous_save);  // fil
  883.           previous_save[0] = '\0';
  884.           cache_rstr(cache->olddat, previous_save);  // save
  885.           if (return_save != NULL) {
  886.             strcpybuff(return_save, previous_save);
  887.           }
  888.         }
  889.         if (cache->version >= 5) {
  890.           r.headers = cache_rstr_addr(cache->olddat);
  891.         }
  892.         //
  893.         cache_rstr(cache->olddat,check);
  894.         if (strcmp(check,"HTS")==0) {           /* intΘgritΘ OK */
  895.           ok=1;
  896.         }
  897.         cache_rLLint(cache->olddat,&size_read);       /* lire size pour Ωtre s√r de la taille dΘclarΘe (rΘΘcrire) */
  898.         if (size_read>0) {                         /* si inscrite ici */
  899.           r.size=size_read;
  900.         } else {                              /* pas de donnΘes directement dans le cache, fichier prΘsent? */
  901.           if (r.statuscode!=200)
  902.             header_only=1;          /* que l'en tΩte ici! */
  903.         }
  904.       }
  905.  
  906.       /* Remplir certains champs */
  907.       r.totalsize=r.size;
  908.  
  909.       // lecture du header (y compris le statuscode)
  910.       /*if (fread((char*) &r,1,sizeof(htsblk),cache->olddat)==sizeof(htsblk)) { // lire tout (y compris statuscode etc)*/
  911.       if (ok) {
  912.         // sΘcuritΘ
  913.         r.adr=NULL;
  914.         r.out=NULL;
  915.         ////r.location=NULL;  non, fixΘe lors des 301 ou 302
  916.         r.fp=NULL;
  917.         
  918.         if ( (r.statuscode>=0) && (r.statuscode<=999)
  919.           && (r.notmodified>=0)  && (r.notmodified<=9) ) {   // petite vΘrif intΘgritΘ
  920.           if ((save) && (!header_only) ) {     /* ne pas lire uniquement header */
  921.             //int to_file=0;
  922.             
  923.             r.adr=NULL; r.soc=INVALID_SOCKET; 
  924.             // // r.location=NULL;
  925.             
  926. #if HTS_DIRECTDISK
  927.             // Court-circuit:
  928.             // Peut-on stocker le fichier directement sur disque?
  929.             if (!readonly && r.statuscode==200 && !is_hypertext_mime(r.contenttype, fil) && strnotempty(save)) {    // pas HTML, Θcrire sur disk directement
  930.               int ok=0;
  931.               
  932.               r.is_write=1;    // Θcrire
  933.               if (fexist(fconv(save))) {  // un fichier existe dΘja
  934.                 //if (fsize(fconv(save))==r.size) {  // mΩme taille -- NON tant pis (taille mal declaree)
  935.                 ok=1;    // plus rien α faire
  936.                 filenote(save,NULL);        // noter comme connu
  937.                 //xxusercommand(opt,0,NULL,save,adr,fil);
  938.                 //}
  939.               }
  940.               
  941.               if ((pos<0) && (!ok)) { // Pas de donnΘe en cache et fichier introuvable : erreur!
  942.                 if (opt->norecatch) {
  943.                   filecreateempty(save);
  944.                   //
  945.                   r.statuscode=-1;
  946.                   strcpybuff(r.msg,"File deleted by user not recaught");
  947.                   ok=1;     // ne pas rΘcupΘrer (et pas d'erreur)
  948.                 } else {
  949.                   r.statuscode=-1;
  950.                   strcpybuff(r.msg,"Previous cache file not found");
  951.                   ok=1;    // ne pas rΘcupΘrer
  952.                 }
  953.               }
  954.               
  955.               if (!ok) {  
  956.                 r.out=filecreate(save);
  957. #if HDEBUG
  958.                 printf("direct-disk: %s\n",save);
  959. #endif
  960.                 if (r.out!=NULL) {
  961.                   char BIGSTK buff[32768+4];
  962.                   LLint size = r.size;
  963.                   if (size > 0) {
  964.                     INTsys nl;
  965.                     do {
  966.                       nl=fread(buff,1,(INTsys) minimum(size,32768),cache->olddat);
  967.                       if (nl>0) {
  968.                         size-=nl; 
  969.                         if ((INTsys)fwrite(buff,1,(INTsys)nl,r.out)!=nl) {  // erreur
  970.                           r.statuscode=-1;
  971.                           strcpybuff(r.msg,"Cache Read Error : Read To Disk");
  972.                         }
  973.                       }
  974.                     } while((nl>0) && (size>0) && (r.statuscode!=-1));
  975.                   }
  976.                   
  977.                   fclose(r.out);
  978.                   r.out=NULL;
  979. #if HTS_WIN==0
  980.                   chmod(save,HTS_ACCESS_FILE);      
  981. #endif          
  982.                   //xxusercommand(opt,0,NULL,fconv(save), adr, fil);
  983.                 } else {
  984.                   r.statuscode=-1;
  985.                   strcpybuff(r.msg,"Cache Write Error : Unable to Create File");
  986.                   //printf("%s\n",save);
  987.                 }
  988.               }
  989.               
  990.             } else
  991. #endif
  992.             { // lire en mΘmoire
  993.               
  994.               if (pos<0) {
  995.                 if (strnotempty(save)) { // Pas de donnΘe en cache, bizarre car html!!!
  996.                   r.statuscode=-1;
  997.                   strcpybuff(r.msg,"Previous cache file not found (2)");
  998.                 } else {                 /* Read in memory from cache */
  999.                   if (strnotempty(return_save) && fexist(return_save)) {
  1000.                     FILE* fp = fopen(fconv(return_save), "rb");
  1001.                     if (fp != NULL) {
  1002.                       r.adr=(char*) malloct((INTsys)r.size + 4);
  1003.                       if (adr != NULL) {
  1004.                         if (r.size > 0 && fread(r.adr, 1, (INTsys) r.size, fp) != r.size) {
  1005.                           r.statuscode=-1;
  1006.                           strcpybuff(r.msg,"Read error in cache disk data");
  1007.                         }
  1008.                       } else {
  1009.                         r.statuscode=-1;
  1010.                         strcpybuff(r.msg,"Read error (memory exhausted) from cache");
  1011.                       }
  1012.                       fclose(fp);
  1013.                     }
  1014.                   } else {
  1015.                     r.statuscode=-1;
  1016.                     strcpybuff(r.msg,"Cache file not found on disk");
  1017.                   }
  1018.                 }
  1019.               } else {
  1020.                 // lire fichier (d'un coup)
  1021.                 r.adr=(char*) malloct((INTsys)r.size+4);
  1022.                 if (r.adr!=NULL) {
  1023.                   if (fread(r.adr,1,(INTsys)r.size,cache->olddat)!=r.size) {  // erreur
  1024.                     freet(r.adr);
  1025.                     r.adr=NULL;
  1026.                     r.statuscode=-1;
  1027.                     strcpybuff(r.msg,"Cache Read Error : Read Data");
  1028.                   } else
  1029.                     *(r.adr+r.size)='\0';
  1030.                   //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  1031.                 } else {  // erreur
  1032.                   r.statuscode=-1;
  1033.                   strcpybuff(r.msg,"Cache Memory Error");
  1034.                 }
  1035.               }
  1036.             }
  1037.           }    // si save==null, ne rien charger (juste en tΩte)
  1038.         } else {
  1039. #if DEBUGCA
  1040.           printf("Cache Read Error : Bad Data");
  1041. #endif
  1042.           r.statuscode=-1;
  1043.           strcpybuff(r.msg,"Cache Read Error : Bad Data");
  1044.         }
  1045.       } else {  // erreur
  1046. #if DEBUGCA
  1047.         printf("Cache Read Error : Read Header");
  1048. #endif
  1049.         r.statuscode=-1;
  1050.         strcpybuff(r.msg,"Cache Read Error : Read Header");
  1051.       }
  1052.     } else {
  1053. #if DEBUGCA
  1054.       printf("Cache Read Error : Seek Failed");
  1055. #endif
  1056.       r.statuscode=-1;
  1057.       strcpybuff(r.msg,"Cache Read Error : Seek Failed");
  1058.     }
  1059.   } else {
  1060. #if DEBUGCA
  1061.     printf("File Cache Not Found");
  1062. #endif
  1063.     r.statuscode=-1;
  1064.     strcpybuff(r.msg,"File Cache Entry Not Found");
  1065.   }
  1066.   if (!location) {   /* don't export internal buffer */
  1067.     r.location = NULL;
  1068.   }
  1069.   return r;
  1070. }
  1071.  
  1072. /* write (string1-string2)-data in cache */
  1073. /* 0 if failed */
  1074. int cache_writedata(FILE* cache_ndx,FILE* cache_dat,char* str1,char* str2,char* outbuff,int len) {
  1075.   if (cache_dat) {
  1076.     char BIGSTK buff[HTS_URLMAXSIZE*4];
  1077.     char s[256];
  1078.     int pos;
  1079.     fflush(cache_dat); fflush(cache_ndx);
  1080.     pos=ftell(cache_dat);
  1081.     /* first write data */
  1082.     if (cache_wint(cache_dat,len)!=-1) {       // length
  1083.       if ((INTsys)fwrite(outbuff,1,(INTsys)len,cache_dat) == (INTsys) len) {   // data
  1084.         /* then write index */
  1085.         sprintf(s,"%d\n",pos);
  1086.         buff[0]='\0'; strcatbuff(buff,str1); strcatbuff(buff,"\n"); strcatbuff(buff,str2); strcatbuff(buff,"\n");
  1087.         cache_wstr(cache_ndx,buff);
  1088.         if (fwrite(s,1,(INTsys)strlen(s),cache_ndx) == strlen(s)) {
  1089.           fflush(cache_dat); fflush(cache_ndx);
  1090.           return 1;
  1091.         }
  1092.       }
  1093.     }
  1094.   }
  1095.   return 0;
  1096. }
  1097.  
  1098. /* read the data corresponding to (string1-string2) in cache */
  1099. /* 0 if failed */
  1100. int cache_readdata(cache_back* cache,char* str1,char* str2,char** inbuff,int* inlen) {
  1101. #if HTS_FAST_CACHE
  1102.   if (cache->hashtable) {
  1103.     char BIGSTK buff[HTS_URLMAXSIZE*4];
  1104.     long int pos;
  1105.     strcpybuff(buff,str1); strcatbuff(buff,str2);
  1106.     if (inthash_read((inthash)cache->hashtable,buff,(long int*)&pos)) {
  1107.       if (fseek(cache->olddat,((pos>0)?pos:(-pos)),SEEK_SET) == 0) {
  1108.         INTsys len;
  1109.         cache_rint(cache->olddat,&len);
  1110.         if (len>0) {
  1111.           char* mem_buff=(char*)malloct(len+4);    /* Plus byte 0 */
  1112.           if (mem_buff) {
  1113.             if ((INTsys)fread(mem_buff,1,len,cache->olddat)==len) { // lire tout (y compris statuscode etc)*/
  1114.               *inbuff=mem_buff;
  1115.               *inlen=len;
  1116.               return 1;
  1117.             } else
  1118.               freet(mem_buff);
  1119.           }
  1120.         }
  1121.       }
  1122.     }
  1123.   }
  1124. #endif
  1125.   *inbuff=NULL;
  1126.   *inlen=0;
  1127.   return 0;
  1128. }
  1129.  
  1130. // renvoyer uniquement en tΩte, ou NULL si erreur
  1131. // return NULL upon error, and set -1 to r.statuscode
  1132. htsblk* cache_header(httrackp* opt,cache_back* cache,char* adr,char* fil,htsblk* r) {
  1133.   *r=cache_read(opt,cache,adr,fil,NULL,NULL);              // test uniquement
  1134.   if (r->statuscode != -1)
  1135.     return r;
  1136.   else
  1137.     return NULL;
  1138. }
  1139.  
  1140.  
  1141. // Initialisation du cache: crΘer nouveau, renomer ancien, charger..
  1142. void cache_init(cache_back* cache,httrackp* opt) {
  1143.   // ---
  1144.   // utilisation du cache: renommer ancien Θventuel et charger index
  1145.   if (opt->cache) {
  1146. #if DEBUGCA
  1147.     printf("cache init: ");
  1148. #endif
  1149.     if (!cache->ro) {
  1150. #if HTS_WIN
  1151.       mkdir(fconcat(opt->path_log,"hts-cache"));
  1152. #else
  1153.       mkdir(fconcat(opt->path_log,"hts-cache"),HTS_PROTECT_FOLDER);
  1154. #endif
  1155.       if ((fexist(fconcat(opt->path_log,"hts-cache/new.zip")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  1156.         /* Previous cache from the previous cache version */
  1157. #if 0
  1158.         /* No.. reuse with old httrack releases! */
  1159.         if (fexist(fconcat(opt->path_log,"hts-cache/old.dat")))
  1160.           remove(fconcat(opt->path_log,"hts-cache/old.dat"));
  1161.         if (fexist(fconcat(opt->path_log,"hts-cache/old.ndx")))
  1162.           remove(fconcat(opt->path_log,"hts-cache/old.ndx"));
  1163. #endif
  1164.         /* Previous cache version */
  1165.         if ((fexist(fconcat(opt->path_log,"hts-cache/new.dat"))) && (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  1166.           rename(fconcat(opt->path_log,"hts-cache/new.dat"),fconcat(opt->path_log,"hts-cache/old.dat"));
  1167.           rename(fconcat(opt->path_log,"hts-cache/new.ndx"),fconcat(opt->path_log,"hts-cache/old.ndx"));
  1168.         }
  1169.  
  1170.         /* Remove OLD cache */
  1171.         if (fexist(fconcat(opt->path_log,"hts-cache/old.zip")))
  1172.           remove(fconcat(opt->path_log,"hts-cache/old.zip"));
  1173.         
  1174.         /* Rename */
  1175.         rename(fconcat(opt->path_log,"hts-cache/new.zip"),fconcat(opt->path_log,"hts-cache/old.zip"));
  1176.       }
  1177.       else if ((fexist(fconcat(opt->path_log,"hts-cache/new.dat"))) && (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))) {  // il existe dΘja un cache prΘcΘdent.. renommer
  1178. #if DEBUGCA
  1179.         printf("work with former cache\n");
  1180. #endif
  1181.         if (fexist(fconcat(opt->path_log,"hts-cache/old.dat")))
  1182.           remove(fconcat(opt->path_log,"hts-cache/old.dat"));
  1183.         if (fexist(fconcat(opt->path_log,"hts-cache/old.ndx")))
  1184.           remove(fconcat(opt->path_log,"hts-cache/old.ndx"));
  1185.         
  1186.         rename(fconcat(opt->path_log,"hts-cache/new.dat"),fconcat(opt->path_log,"hts-cache/old.dat"));
  1187.         rename(fconcat(opt->path_log,"hts-cache/new.ndx"),fconcat(opt->path_log,"hts-cache/old.ndx"));
  1188.       } else {  // un des deux (ou les deux) fichiers cache absents: effacer l'autre Θventuel
  1189. #if DEBUGCA
  1190.         printf("new cache\n");
  1191. #endif
  1192.         if (fexist(fconcat(opt->path_log,"hts-cache/new.dat")))
  1193.           remove(fconcat(opt->path_log,"hts-cache/new.dat"));
  1194.         if (fexist(fconcat(opt->path_log,"hts-cache/new.ndx")))
  1195.           remove(fconcat(opt->path_log,"hts-cache/new.ndx"));
  1196.       }
  1197.     }
  1198.     
  1199.     // charger index cache prΘcΘdent
  1200.     if (
  1201.       (
  1202.       !cache->ro &&
  1203.       fsize(fconcat(opt->path_log,"hts-cache/old.zip")) > 0 
  1204.       )
  1205.       ||
  1206.       (
  1207.       cache->ro &&
  1208.       fsize(fconcat(opt->path_log,"hts-cache/new.zip")) > 0
  1209.       )
  1210.       ) 
  1211.     {
  1212.       if (!cache->ro) {
  1213.         cache->zipInput = unzOpen(fconcat(opt->path_log,"hts-cache/old.zip"));
  1214.       } else {
  1215.         cache->zipInput = unzOpen(fconcat(opt->path_log,"hts-cache/new.zip"));
  1216.       }
  1217.       
  1218.       // Corrupted ZIP file ? Try to repair!
  1219.       if (cache->zipInput == NULL && !cache->ro) {
  1220.           char* name;
  1221.           uLong repaired = 0;
  1222.           uLong repairedBytes = 0;
  1223.           if (!cache->ro) {
  1224.             name = fconcat(opt->path_log,"hts-cache/old.zip");
  1225.           } else {
  1226.             name = fconcat(opt->path_log,"hts-cache/new.zip");
  1227.           }
  1228.           if (opt->log) {
  1229.             fspc(opt->log,"warning"); fprintf(opt->log,"Cache: damaged cache, trying to repair"LF);
  1230.             fflush(opt->log);
  1231.           }
  1232.           if (unzRepair(name, 
  1233.             fconcat(opt->path_log,"hts-cache/repair.zip"),
  1234.             fconcat(opt->path_log,"hts-cache/repair.tmp"),
  1235.             &repaired, &repairedBytes
  1236.             ) == Z_OK) {
  1237.             unlink(name);
  1238.             rename(fconcat(opt->path_log,"hts-cache/repair.zip"), name);
  1239.             cache->zipInput = unzOpen(name);
  1240.             if (opt->log) {
  1241.               fspc(opt->log,"warning"); fprintf(opt->log,"Cache: %d bytes successfully recovered in %d entries"LF, 
  1242.                 (int) repairedBytes, (int) repaired);
  1243.               fflush(opt->log);
  1244.             }
  1245.           } else {
  1246.             if (opt->log) {
  1247.               fspc(opt->log,"warning"); fprintf(opt->log,"Cache: could not repair the cache"LF);
  1248.               fflush(opt->log);
  1249.             }
  1250.           }
  1251.       }
  1252.       
  1253.       // Opened ?
  1254.       if (cache->zipInput!=NULL) {
  1255.         
  1256.         /* Ready directory entries */
  1257.         if (unzGoToFirstFile((unzFile) cache->zipInput) == Z_OK) {
  1258.           char comment[128];
  1259.           char BIGSTK filename[HTS_URLMAXSIZE * 4];
  1260.           int entries = 0;
  1261.           memset(comment, 0, sizeof(comment));       // for truncated reads
  1262.           do  {
  1263.             int readSizeHeader = 0;
  1264.             filename[0] = '\0';
  1265.             comment[0] = '\0';
  1266.             if (unzOpenCurrentFile((unzFile) cache->zipInput) == Z_OK) {
  1267.               if (
  1268.                 (readSizeHeader = unzGetLocalExtrafield((unzFile) cache->zipInput, comment, sizeof(comment) - 2)) > 0
  1269.                 &&
  1270.                 unzGetCurrentFileInfo((unzFile) cache->zipInput, NULL, filename, sizeof(filename) - 2, NULL, 0, NULL, 0) == Z_OK
  1271.                 ) 
  1272.               {
  1273.                 long int pos = (long int) unzGetOffset((unzFile) cache->zipInput);
  1274.                 assertf(readSizeHeader < sizeof(comment));
  1275.                 comment[readSizeHeader] = '\0';
  1276.                 entries++;
  1277.                 if (pos > 0) {
  1278.                   int dataincache = 0;    // data in cache ?
  1279.                   char* filenameIndex = filename;
  1280.                   if (strfield(filenameIndex, "http://")) {
  1281.                     filenameIndex += 7;
  1282.                   }
  1283.                   if (comment[0] != '\0') {
  1284.                     int maxLine = 2;
  1285.                     char* a = comment;
  1286.                     while(*a && maxLine-- > 0) {      // parse only few first lines
  1287.                       char BIGSTK line[1024];
  1288.                       line[0] = '\0';
  1289.                       a+=binput(a, line, sizeof(line) - 2);
  1290.                       if (strfield(line, "X-In-Cache:")) {
  1291.                         if (strfield2(line, "X-In-Cache: 1")) {
  1292.                           dataincache = 1;
  1293.                         } else {
  1294.                           dataincache = 0;
  1295.                         }
  1296.                         break;
  1297.                       }
  1298.                     }
  1299.                   }
  1300.                   if (dataincache)
  1301.                     inthash_add((inthash)cache->hashtable, filenameIndex, pos);
  1302.                   else
  1303.                     inthash_add((inthash)cache->hashtable, filenameIndex, -pos);
  1304.                 } else {
  1305.                   if (opt->log!=NULL) {
  1306.                     fspc(opt->log,"warning"); fprintf(opt->log,"Corrupted cache meta entry #%d"LF, (int)entries);
  1307.                   }
  1308.                 }
  1309.               } else {
  1310.                 if (opt->log!=NULL) {
  1311.                   fspc(opt->log,"warning"); fprintf(opt->log,"Corrupted cache entry #%d"LF, (int)entries);
  1312.                 }
  1313.               }
  1314.               unzCloseCurrentFile((unzFile) cache->zipInput);
  1315.             } else {
  1316.               if (opt->log!=NULL) {
  1317.                 fspc(opt->log,"warning"); fprintf(opt->log,"Corrupted cache entry #%d"LF, (int)entries);
  1318.               }
  1319.             }
  1320.           } while( unzGoToNextFile((unzFile) cache->zipInput) == Z_OK );
  1321.           if ((opt->debug>0) && (opt->log!=NULL)) {
  1322.             fspc(opt->log,"debug"); fprintf(opt->log,"Cache index loaded: %d entries loaded"LF, (int)entries);
  1323.           }
  1324.           opt->is_update=1;        // signaler comme update
  1325.           
  1326.         }    
  1327.         
  1328.       }
  1329.       
  1330.     } else if (
  1331.       (
  1332.       !cache->ro &&
  1333.       fsize(fconcat(opt->path_log,"hts-cache/old.dat")) >=0 && fsize(fconcat(opt->path_log,"hts-cache/old.ndx")) >0
  1334.       )
  1335.       ||
  1336.       (
  1337.       cache->ro &&
  1338.       fsize(fconcat(opt->path_log,"hts-cache/new.dat")) >=0 && fsize(fconcat(opt->path_log,"hts-cache/new.ndx")) > 0
  1339.       )
  1340.       ) {
  1341.       FILE* oldndx=NULL;
  1342. #if DEBUGCA
  1343.       printf("..load cache\n");
  1344. #endif
  1345.       if (!cache->ro) {
  1346.         cache->olddat=fopen(fconcat(opt->path_log,"hts-cache/old.dat"),"rb");        
  1347.         oldndx=fopen(fconcat(opt->path_log,"hts-cache/old.ndx"),"rb");        
  1348.       } else {
  1349.         cache->olddat=fopen(fconcat(opt->path_log,"hts-cache/new.dat"),"rb");        
  1350.         oldndx=fopen(fconcat(opt->path_log,"hts-cache/new.ndx"),"rb");        
  1351.       }
  1352.       // les deux doivent Ωtre ouvrables
  1353.       if ((cache->olddat==NULL) && (oldndx!=NULL)) {
  1354.         fclose(oldndx);
  1355.         oldndx=NULL;
  1356.       }
  1357.       if ((cache->olddat!=NULL) && (oldndx==NULL)) {
  1358.         fclose(cache->olddat);
  1359.         cache->olddat=NULL;
  1360.       }
  1361.       // lire index
  1362.       if (oldndx!=NULL) {
  1363.         int buffl;
  1364.         fclose(oldndx); oldndx=NULL;
  1365.         // lire ndx, et lastmodified
  1366.         if (!cache->ro) {
  1367.           buffl=fsize(fconcat(opt->path_log,"hts-cache/old.ndx"));
  1368.           cache->use=readfile(fconcat(opt->path_log,"hts-cache/old.ndx"));
  1369.         } else {
  1370.           buffl=fsize(fconcat(opt->path_log,"hts-cache/new.ndx"));
  1371.           cache->use=readfile(fconcat(opt->path_log,"hts-cache/new.ndx"));
  1372.         }
  1373.         if (cache->use!=NULL) {
  1374.           char firstline[256];
  1375.           char* a=cache->use;
  1376.           a+=cache_brstr(a,firstline);
  1377.           if (strncmp(firstline,"CACHE-",6)==0) {       // Nouvelle version du cache
  1378.             if (strncmp(firstline,"CACHE-1.",8)==0) {      // Version 1.1x
  1379.               cache->version=(int)(firstline[8]-'0');           // cache 1.x
  1380.               if (cache->version <= 5) {
  1381.                 a+=cache_brstr(a,firstline);
  1382.                 strcpybuff(cache->lastmodified,firstline);
  1383.               } else {
  1384.                 if (opt->errlog) {
  1385.                   fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: version 1.%d not supported, ignoring current cache"LF,cache->version);
  1386.                   fflush(opt->errlog);
  1387.                 }
  1388.                 fclose(cache->olddat);
  1389.                 cache->olddat=NULL;
  1390.                 freet(cache->use);
  1391.                 cache->use=NULL;
  1392.               }
  1393.             } else {        // non supportΘ
  1394.               if (opt->errlog) {
  1395.                 fspc(opt->errlog,"error"); fprintf(opt->errlog,"Cache: %s not supported, ignoring current cache"LF,firstline);
  1396.                 fflush(opt->errlog);
  1397.               }
  1398.               fclose(cache->olddat);
  1399.               cache->olddat=NULL;
  1400.               freet(cache->use);
  1401.               cache->use=NULL;
  1402.             }
  1403.             /* */
  1404.           } else {              // Vieille version du cache
  1405.             /* */
  1406.             if (opt->log) {
  1407.               fspc(opt->log,"warning"); fprintf(opt->log,"Cache: importing old cache format"LF);
  1408.               fflush(opt->log);
  1409.             }
  1410.             cache->version=0;        // cache 1.0
  1411.             strcpybuff(cache->lastmodified,firstline); 
  1412.           }
  1413.           opt->is_update=1;        // signaler comme update
  1414.           
  1415.           /* Create hash table for the cache (MUCH FASTER!) */
  1416. #if HTS_FAST_CACHE
  1417.           if (cache->use) {
  1418.             char BIGSTK line[HTS_URLMAXSIZE*2];
  1419.             char linepos[256];
  1420.             int  pos;
  1421.             while ( (a!=NULL) && (a < (cache->use+buffl) ) ) {
  1422.               a=strchr(a+1,'\n');     /* start of line */
  1423.               if (a) {
  1424.                 a++;
  1425.                 /* read "host/file" */
  1426.                 a+=binput(a,line,HTS_URLMAXSIZE);
  1427.                 a+=binput(a,line+strlen(line),HTS_URLMAXSIZE);
  1428.                 /* read position */
  1429.                 a+=binput(a,linepos,200);
  1430.                 sscanf(linepos,"%d",&pos);
  1431.                 inthash_add((inthash)cache->hashtable,line,pos);
  1432.               }
  1433.             }
  1434.             /* Not needed anymore! */
  1435.             freet(cache->use);
  1436.             cache->use=NULL;
  1437.           }
  1438. #endif
  1439.         }
  1440.       }
  1441.       }  // taille cache>0
  1442.       
  1443. #if DEBUGCA
  1444.       printf("..create cache\n");
  1445. #endif
  1446.       if (!cache->ro) {
  1447.         // ouvrir caches actuels
  1448.         structcheck(fconcat(opt->path_log, "hts-cache/"));
  1449.         
  1450.         if (1) {
  1451.           /* Create ZIP file cache */
  1452.           cache->zipOutput = (void*) zipOpen(fconcat(opt->path_log,"hts-cache/new.zip"), 0);
  1453.  
  1454.           if (cache->zipOutput != NULL) {
  1455.             // supprimer old.lst
  1456.             if (fexist(fconcat(opt->path_log,"hts-cache/old.lst")))
  1457.               remove(fconcat(opt->path_log,"hts-cache/old.lst"));
  1458.             // renommer
  1459.             if (fexist(fconcat(opt->path_log,"hts-cache/new.lst")))
  1460.               rename(fconcat(opt->path_log,"hts-cache/new.lst"),fconcat(opt->path_log,"hts-cache/old.lst"));
  1461.             // ouvrir
  1462.             cache->lst=fopen(fconcat(opt->path_log,"hts-cache/new.lst"),"wb");
  1463.             {
  1464.               filecreate_params tmp;
  1465.               strcpybuff(tmp.path,opt->path_html);    // chemin
  1466.               tmp.lst=cache->lst;                 // fichier lst
  1467.               filenote("",&tmp);        // initialiser filecreate
  1468.             }
  1469.             
  1470.             // supprimer old.txt
  1471.             if (fexist(fconcat(opt->path_log,"hts-cache/old.txt")))
  1472.               remove(fconcat(opt->path_log,"hts-cache/old.txt"));
  1473.             // renommer
  1474.             if (fexist(fconcat(opt->path_log,"hts-cache/new.txt")))
  1475.               rename(fconcat(opt->path_log,"hts-cache/new.txt"),fconcat(opt->path_log,"hts-cache/old.txt"));
  1476.             // ouvrir
  1477.             cache->txt=fopen(fconcat(opt->path_log,"hts-cache/new.txt"),"wb");
  1478.             if (cache->txt) {
  1479.               fprintf(cache->txt,"date\tsize'/'remotesize\tflags(request:Update,Range state:File response:Modified,Chunked,gZipped)\t");
  1480.               fprintf(cache->txt,"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"LF);
  1481.             }
  1482.           }
  1483.         } else {
  1484.           cache->dat=fopen(fconcat(opt->path_log,"hts-cache/new.dat"),"wb");        
  1485.           cache->ndx=fopen(fconcat(opt->path_log,"hts-cache/new.ndx"),"wb");        
  1486.           // les deux doivent Ωtre ouvrables
  1487.           if ((cache->dat==NULL) && (cache->ndx!=NULL)) {
  1488.             fclose(cache->ndx);
  1489.             cache->ndx=NULL;
  1490.           }
  1491.           if ((cache->dat!=NULL) && (cache->ndx==NULL)) {
  1492.             fclose(cache->dat);
  1493.             cache->dat=NULL;
  1494.           }
  1495.           
  1496.           if (cache->ndx!=NULL) {
  1497.             char s[256];
  1498.             
  1499.             cache_wstr(cache->dat,"CACHE-1.5");
  1500.             fflush(cache->dat);
  1501.             cache_wstr(cache->ndx,"CACHE-1.5");
  1502.             fflush(cache->ndx);
  1503.             //
  1504.             time_gmt_rfc822(s);   // date et heure actuelle GMT pour If-Modified-Since..
  1505.             cache_wstr(cache->ndx,s);        
  1506.             fflush(cache->ndx);    // un petit fflush au cas o∙
  1507.             
  1508.             // supprimer old.lst
  1509.             if (fexist(fconcat(opt->path_log,"hts-cache/old.lst")))
  1510.               remove(fconcat(opt->path_log,"hts-cache/old.lst"));
  1511.             // renommer
  1512.             if (fexist(fconcat(opt->path_log,"hts-cache/new.lst")))
  1513.               rename(fconcat(opt->path_log,"hts-cache/new.lst"),fconcat(opt->path_log,"hts-cache/old.lst"));
  1514.             // ouvrir
  1515.             cache->lst=fopen(fconcat(opt->path_log,"hts-cache/new.lst"),"wb");
  1516.             {
  1517.               filecreate_params tmp;
  1518.               strcpybuff(tmp.path,opt->path_html);    // chemin
  1519.               tmp.lst=cache->lst;                 // fichier lst
  1520.               filenote("",&tmp);        // initialiser filecreate
  1521.             }
  1522.             
  1523.             // supprimer old.txt
  1524.             if (fexist(fconcat(opt->path_log,"hts-cache/old.txt")))
  1525.               remove(fconcat(opt->path_log,"hts-cache/old.txt"));
  1526.             // renommer
  1527.             if (fexist(fconcat(opt->path_log,"hts-cache/new.txt")))
  1528.               rename(fconcat(opt->path_log,"hts-cache/new.txt"),fconcat(opt->path_log,"hts-cache/old.txt"));
  1529.             // ouvrir
  1530.             cache->txt=fopen(fconcat(opt->path_log,"hts-cache/new.txt"),"wb");
  1531.             if (cache->txt) {
  1532.               fprintf(cache->txt,"date\tsize'/'remotesize\tflags(request:Update,Range state:File response:Modified,Chunked,gZipped)\t");
  1533.               fprintf(cache->txt,"statuscode\tstatus ('servermsg')\tMIME\tEtag|Date\tURL\tlocalfile\t(from URL)"LF);
  1534.             }
  1535.             
  1536.             // test
  1537.             // cache_writedata(cache->ndx,cache->dat,"//[TEST]//","test1","TEST PIPO",9);
  1538.           }
  1539.         }
  1540.         
  1541.       } else {
  1542.         cache->lst = cache->dat = cache->ndx = NULL;
  1543.       }
  1544.       
  1545.   }
  1546.   
  1547. }
  1548.  
  1549.  
  1550.  
  1551.  
  1552. // lire un fichier.. (compatible \0)
  1553. char* readfile(char* fil) {
  1554.   char* adr=NULL;
  1555.   INTsys len=0;
  1556.   len=fsize(fil);
  1557.   if (len >= 0) {  // exists
  1558.     FILE* fp;
  1559.     fp=fopen(fconv(fil),"rb");
  1560.     if (fp!=NULL) {  // n'existe pas (!)
  1561.       adr=(char*) malloct(len+1);
  1562.       if (adr!=NULL) {
  1563.         if (len > 0 && (INTsys)fread(adr,1,len,fp) != len) {    // fichier endommagΘ ?
  1564.           freet(adr);
  1565.           adr=NULL;
  1566.         } else
  1567.           *(adr+len)='\0';
  1568.       }
  1569.       fclose(fp);
  1570.     }
  1571.   }
  1572.   return adr;
  1573. }
  1574.  
  1575. char* readfile_or(char* fil,char* defaultdata) {
  1576.   char* realfile=fil;
  1577.   char* ret;
  1578.   if (!fexist(fil))
  1579.     realfile=fconcat(hts_rootdir(NULL),fil);
  1580.   ret=readfile(realfile);
  1581.   if (ret)
  1582.     return ret;
  1583.   else {
  1584.     char *adr=malloct(strlen(defaultdata)+2);
  1585.     if (adr) {
  1586.       strcpybuff(adr,defaultdata);
  1587.       return adr;
  1588.     }
  1589.   }
  1590.   return NULL;
  1591. }
  1592.  
  1593. // Θcriture/lecture d'une chaεne sur un fichier
  1594. // -1 : erreur, sinon 0
  1595. int cache_wstr(FILE* fp,char* s) {
  1596.   INTsys i;
  1597.   char buff[256+4];
  1598.   i = s != NULL ? strlen(s) : 0;
  1599.   sprintf(buff,INTsysP "\n",i);
  1600.   if (fwrite(buff,1,(INTsys)strlen(buff),fp) != strlen(buff))
  1601.     return -1;
  1602.   if (i > 0 && (INTsys)fwrite(s,1,i,fp) != i)
  1603.     return -1;
  1604.   return 0;
  1605. }
  1606. void cache_rstr(FILE* fp,char* s) {
  1607.   INTsys i;
  1608.   char buff[256+4];
  1609.   linput(fp,buff,256);
  1610.   sscanf(buff,INTsysP,&i);
  1611.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  1612.     i=0;
  1613.   if (i>0) {
  1614.     if ((int) fread(s,1,i,fp) != i) {
  1615.       int fread_cache_failed = 0;
  1616.       assertf(fread_cache_failed);
  1617.     }
  1618.   }
  1619.   *(s+i)='\0';
  1620. }
  1621. char* cache_rstr_addr(FILE* fp) {
  1622.   INTsys i;
  1623.   char* addr = NULL;
  1624.   char buff[256+4];
  1625.   linput(fp,buff,256);
  1626.   sscanf(buff,INTsysP,&i);
  1627.   if (i < 0 || i > 32768)    /* error, something nasty happened */
  1628.     i=0;
  1629.   if (i > 0) {
  1630.     addr = malloct(i + 1);
  1631.     if (addr != NULL) {
  1632.       if ((int) fread(addr,1,i,fp) != i) {
  1633.         int fread_cache_failed = 0;
  1634.         assertf(fread_cache_failed);
  1635.       }
  1636.       *(addr+i)='\0';
  1637.     }
  1638.   }
  1639.   return addr;
  1640. }
  1641. int cache_brstr(char* adr,char* s) {
  1642.   int i;
  1643.   int off;
  1644.   char buff[256+4];
  1645.   off=binput(adr,buff,256);
  1646.   adr+=off;
  1647.   sscanf(buff,"%d",&i);
  1648.   if (i>0)
  1649.     strncpy(s,adr,i);
  1650.   *(s+i)='\0';
  1651.   off+=i;
  1652.   return off;
  1653. }
  1654. int cache_quickbrstr(char* adr,char* s) {
  1655.   int i;
  1656.   int off;
  1657.   char buff[256+4];
  1658.   off=binput(adr,buff,256);
  1659.   adr+=off;
  1660.   sscanf(buff,"%d",&i);
  1661.   if (i>0)
  1662.     strncpy(s,adr,i);
  1663.   *(s+i)='\0';
  1664.   off+=i;
  1665.   return off;
  1666. }
  1667. /* idem, mais en int */
  1668. int cache_brint(char* adr,int* i) {
  1669.   char s[256];
  1670.   int r=cache_brstr(adr,s);
  1671.   if (r!=-1)
  1672.     sscanf(s,"%d",i);
  1673.   return r;
  1674. }
  1675. void cache_rint(FILE* fp,int* i) {
  1676.   char s[256];
  1677.   cache_rstr(fp,s);
  1678.   sscanf(s,"%d",i);
  1679. }
  1680. int cache_wint(FILE* fp,int i) {
  1681.   char s[256];
  1682.   sprintf(s,"%d",(int) i);
  1683.   return cache_wstr(fp,s);
  1684. }
  1685. void cache_rLLint(FILE* fp,LLint* i) {
  1686.   char s[256];
  1687.   cache_rstr(fp,s);
  1688.   sscanf(s,LLintP,i);
  1689. }
  1690. int cache_wLLint(FILE* fp,LLint i) {
  1691.   char s[256];
  1692.   sprintf(s,LLintP,(LLint) i);
  1693.   return cache_wstr(fp,s);
  1694. }
  1695. // -- cache --
  1696.